home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / lib / python2.5 / aifc.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-29  |  30KB  |  1,044 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.5)
  3.  
  4. '''Stuff to parse AIFF-C and AIFF files.
  5.  
  6. Unless explicitly stated otherwise, the description below is true
  7. both for AIFF-C files and AIFF files.
  8.  
  9. An AIFF-C file has the following structure.
  10.  
  11.   +-----------------+
  12.   | FORM            |
  13.   +-----------------+
  14.   | <size>          |
  15.   +----+------------+
  16.   |    | AIFC       |
  17.   |    +------------+
  18.   |    | <chunks>   |
  19.   |    |    .       |
  20.   |    |    .       |
  21.   |    |    .       |
  22.   +----+------------+
  23.  
  24. An AIFF file has the string "AIFF" instead of "AIFC".
  25.  
  26. A chunk consists of an identifier (4 bytes) followed by a size (4 bytes,
  27. big endian order), followed by the data.  The size field does not include
  28. the size of the 8 byte header.
  29.  
  30. The following chunk types are recognized.
  31.  
  32.   FVER
  33.       <version number of AIFF-C defining document> (AIFF-C only).
  34.   MARK
  35.       <# of markers> (2 bytes)
  36.       list of markers:
  37.           <marker ID> (2 bytes, must be > 0)
  38.           <position> (4 bytes)
  39.           <marker name> ("pstring")
  40.   COMM
  41.       <# of channels> (2 bytes)
  42.       <# of sound frames> (4 bytes)
  43.       <size of the samples> (2 bytes)
  44.       <sampling frequency> (10 bytes, IEEE 80-bit extended
  45.           floating point)
  46.       in AIFF-C files only:
  47.       <compression type> (4 bytes)
  48.       <human-readable version of compression type> ("pstring")
  49.   SSND
  50.       <offset> (4 bytes, not used by this program)
  51.       <blocksize> (4 bytes, not used by this program)
  52.       <sound data>
  53.  
  54. A pstring consists of 1 byte length, a string of characters, and 0 or 1
  55. byte pad to make the total length even.
  56.  
  57. Usage.
  58.  
  59. Reading AIFF files:
  60.   f = aifc.open(file, \'r\')
  61. where file is either the name of a file or an open file pointer.
  62. The open file pointer must have methods read(), seek(), and close().
  63. In some types of audio files, if the setpos() method is not used,
  64. the seek() method is not necessary.
  65.  
  66. This returns an instance of a class with the following public methods:
  67.   getnchannels()  -- returns number of audio channels (1 for
  68.              mono, 2 for stereo)
  69.   getsampwidth()  -- returns sample width in bytes
  70.   getframerate()  -- returns sampling frequency
  71.   getnframes()    -- returns number of audio frames
  72.   getcomptype()   -- returns compression type (\'NONE\' for AIFF files)
  73.   getcompname()   -- returns human-readable version of
  74.              compression type (\'not compressed\' for AIFF files)
  75.   getparams() -- returns a tuple consisting of all of the
  76.              above in the above order
  77.   getmarkers()    -- get the list of marks in the audio file or None
  78.              if there are no marks
  79.   getmark(id) -- get mark with the specified id (raises an error
  80.              if the mark does not exist)
  81.   readframes(n)   -- returns at most n frames of audio
  82.   rewind()    -- rewind to the beginning of the audio stream
  83.   setpos(pos) -- seek to the specified position
  84.   tell()      -- return the current position
  85.   close()     -- close the instance (make it unusable)
  86. The position returned by tell(), the position given to setpos() and
  87. the position of marks are all compatible and have nothing to do with
  88. the actual position in the file.
  89. The close() method is called automatically when the class instance
  90. is destroyed.
  91.  
  92. Writing AIFF files:
  93.   f = aifc.open(file, \'w\')
  94. where file is either the name of a file or an open file pointer.
  95. The open file pointer must have methods write(), tell(), seek(), and
  96. close().
  97.  
  98. This returns an instance of a class with the following public methods:
  99.   aiff()      -- create an AIFF file (AIFF-C default)
  100.   aifc()      -- create an AIFF-C file
  101.   setnchannels(n) -- set the number of channels
  102.   setsampwidth(n) -- set the sample width
  103.   setframerate(n) -- set the frame rate
  104.   setnframes(n)   -- set the number of frames
  105.   setcomptype(type, name)
  106.           -- set the compression type and the
  107.              human-readable compression type
  108.   setparams(tuple)
  109.           -- set all parameters at once
  110.   setmark(id, pos, name)
  111.           -- add specified mark to the list of marks
  112.   tell()      -- return current position in output file (useful
  113.              in combination with setmark())
  114.   writeframesraw(data)
  115.           -- write audio frames without pathing up the
  116.              file header
  117.   writeframes(data)
  118.           -- write audio frames and patch up the file header
  119.   close()     -- patch up the file header and close the
  120.              output file
  121. You should set the parameters before the first writeframesraw or
  122. writeframes.  The total number of frames does not need to be set,
  123. but when it is set to the correct value, the header does not have to
  124. be patched up.
  125. It is best to first set all parameters, perhaps possibly the
  126. compression type, and then write audio frames using writeframesraw.
  127. When all frames have been written, either call writeframes(\'\') or
  128. close() to patch up the sizes in the header.
  129. Marks can be added anytime.  If there are any marks, ypu must call
  130. close() after all frames have been written.
  131. The close() method is called automatically when the class instance
  132. is destroyed.
  133.  
  134. When a file is opened with the extension \'.aiff\', an AIFF file is
  135. written, otherwise an AIFF-C file is written.  This default can be
  136. changed by calling aiff() or aifc() before the first writeframes or
  137. writeframesraw.
  138. '''
  139. import struct
  140. import __builtin__
  141. __all__ = [
  142.     'Error',
  143.     'open',
  144.     'openfp']
  145.  
  146. class Error(Exception):
  147.     pass
  148.  
  149. _AIFC_version = 0xA2805140L
  150. _skiplist = ('COMT', 'INST', 'MIDI', 'AESD', 'APPL', 'NAME', 'AUTH', '(c) ', 'ANNO')
  151.  
  152. def _read_long(file):
  153.     
  154.     try:
  155.         return struct.unpack('>l', file.read(4))[0]
  156.     except struct.error:
  157.         raise EOFError
  158.  
  159.  
  160.  
  161. def _read_ulong(file):
  162.     
  163.     try:
  164.         return struct.unpack('>L', file.read(4))[0]
  165.     except struct.error:
  166.         raise EOFError
  167.  
  168.  
  169.  
  170. def _read_short(file):
  171.     
  172.     try:
  173.         return struct.unpack('>h', file.read(2))[0]
  174.     except struct.error:
  175.         raise EOFError
  176.  
  177.  
  178.  
  179. def _read_string(file):
  180.     length = ord(file.read(1))
  181.     if length == 0:
  182.         data = ''
  183.     else:
  184.         data = file.read(length)
  185.     if length & 1 == 0:
  186.         dummy = file.read(1)
  187.     
  188.     return data
  189.  
  190. _HUGE_VAL = 1.79769e+308
  191.  
  192. def _read_float(f):
  193.     expon = _read_short(f)
  194.     sign = 1
  195.     if expon < 0:
  196.         sign = -1
  197.         expon = expon + 32768
  198.     
  199.     himant = _read_ulong(f)
  200.     lomant = _read_ulong(f)
  201.     if himant == himant and lomant == lomant:
  202.         pass
  203.     elif lomant == 0:
  204.         f = 0
  205.     elif expon == 32767:
  206.         f = _HUGE_VAL
  207.     else:
  208.         expon = expon - 16383
  209.         f = (himant * 0x100000000L + lomant) * pow(2, expon - 63)
  210.     return sign * f
  211.  
  212.  
  213. def _write_short(f, x):
  214.     f.write(struct.pack('>h', x))
  215.  
  216.  
  217. def _write_long(f, x):
  218.     f.write(struct.pack('>L', x))
  219.  
  220.  
  221. def _write_string(f, s):
  222.     if len(s) > 255:
  223.         raise ValueError('string exceeds maximum pstring length')
  224.     
  225.     f.write(chr(len(s)))
  226.     f.write(s)
  227.     if len(s) & 1 == 0:
  228.         f.write(chr(0))
  229.     
  230.  
  231.  
  232. def _write_float(f, x):
  233.     import math as math
  234.     if x < 0:
  235.         sign = 32768
  236.         x = x * -1
  237.     else:
  238.         sign = 0
  239.     if x == 0:
  240.         expon = 0
  241.         himant = 0
  242.         lomant = 0
  243.     else:
  244.         (fmant, expon) = math.frexp(x)
  245.         if expon > 16384 or fmant >= 1:
  246.             expon = sign | 32767
  247.             himant = 0
  248.             lomant = 0
  249.         else:
  250.             expon = expon + 16382
  251.             if expon < 0:
  252.                 fmant = math.ldexp(fmant, expon)
  253.                 expon = 0
  254.             
  255.             expon = expon | sign
  256.             fmant = math.ldexp(fmant, 32)
  257.             fsmant = math.floor(fmant)
  258.             himant = long(fsmant)
  259.             fmant = math.ldexp(fmant - fsmant, 32)
  260.             fsmant = math.floor(fmant)
  261.             lomant = long(fsmant)
  262.     _write_short(f, expon)
  263.     _write_long(f, himant)
  264.     _write_long(f, lomant)
  265.  
  266. from chunk import Chunk
  267.  
  268. class Aifc_read:
  269.     
  270.     def initfp(self, file):
  271.         self._version = 0
  272.         self._decomp = None
  273.         self._convert = None
  274.         self._markers = []
  275.         self._soundpos = 0
  276.         self._file = Chunk(file)
  277.         if self._file.getname() != 'FORM':
  278.             raise Error, 'file does not start with FORM id'
  279.         
  280.         formdata = self._file.read(4)
  281.         if formdata == 'AIFF':
  282.             self._aifc = 0
  283.         elif formdata == 'AIFC':
  284.             self._aifc = 1
  285.         else:
  286.             raise Error, 'not an AIFF or AIFF-C file'
  287.         self._comm_chunk_read = 0
  288.         while None:
  289.             self._ssnd_seek_needed = 1
  290.             
  291.             try:
  292.                 chunk = Chunk(self._file)
  293.             except EOFError:
  294.                 break
  295.  
  296.             chunkname = chunk.getname()
  297.             if chunkname == 'COMM':
  298.                 self._read_comm_chunk(chunk)
  299.                 self._comm_chunk_read = 1
  300.             elif chunkname == 'SSND':
  301.                 self._ssnd_chunk = chunk
  302.                 dummy = chunk.read(8)
  303.                 self._ssnd_seek_needed = 0
  304.             elif chunkname == 'FVER':
  305.                 self._version = _read_ulong(chunk)
  306.             elif chunkname == 'MARK':
  307.                 self._readmark(chunk)
  308.             elif chunkname in _skiplist:
  309.                 pass
  310.             else:
  311.                 raise Error, 'unrecognized chunk type ' + chunk.chunkname
  312.             continue
  313.             if not (self._comm_chunk_read) or not (self._ssnd_chunk):
  314.                 raise Error, 'COMM chunk and/or SSND chunk missing'
  315.             
  316.         if self._aifc and self._decomp:
  317.             import cl as cl
  318.             params = [
  319.                 cl.ORIGINAL_FORMAT,
  320.                 0,
  321.                 cl.BITS_PER_COMPONENT,
  322.                 self._sampwidth * 8,
  323.                 cl.FRAME_RATE,
  324.                 self._framerate]
  325.             if self._nchannels == 1:
  326.                 params[1] = cl.MONO
  327.             elif self._nchannels == 2:
  328.                 params[1] = cl.STEREO_INTERLEAVED
  329.             else:
  330.                 raise Error, 'cannot compress more than 2 channels'
  331.             self._decomp.SetParams(params)
  332.         
  333.  
  334.     
  335.     def __init__(self, f):
  336.         if type(f) == type(''):
  337.             f = __builtin__.open(f, 'rb')
  338.         
  339.         self.initfp(f)
  340.  
  341.     
  342.     def getfp(self):
  343.         return self._file
  344.  
  345.     
  346.     def rewind(self):
  347.         self._ssnd_seek_needed = 1
  348.         self._soundpos = 0
  349.  
  350.     
  351.     def close(self):
  352.         if self._decomp:
  353.             self._decomp.CloseDecompressor()
  354.             self._decomp = None
  355.         
  356.         self._file = None
  357.  
  358.     
  359.     def tell(self):
  360.         return self._soundpos
  361.  
  362.     
  363.     def getnchannels(self):
  364.         return self._nchannels
  365.  
  366.     
  367.     def getnframes(self):
  368.         return self._nframes
  369.  
  370.     
  371.     def getsampwidth(self):
  372.         return self._sampwidth
  373.  
  374.     
  375.     def getframerate(self):
  376.         return self._framerate
  377.  
  378.     
  379.     def getcomptype(self):
  380.         return self._comptype
  381.  
  382.     
  383.     def getcompname(self):
  384.         return self._compname
  385.  
  386.     
  387.     def getparams(self):
  388.         return (self.getnchannels(), self.getsampwidth(), self.getframerate(), self.getnframes(), self.getcomptype(), self.getcompname())
  389.  
  390.     
  391.     def getmarkers(self):
  392.         if len(self._markers) == 0:
  393.             return None
  394.         
  395.         return self._markers
  396.  
  397.     
  398.     def getmark(self, id):
  399.         for marker in self._markers:
  400.             if id == marker[0]:
  401.                 return marker
  402.                 continue
  403.         
  404.         raise Error, 'marker %r does not exist' % (id,)
  405.  
  406.     
  407.     def setpos(self, pos):
  408.         if pos < 0 or pos > self._nframes:
  409.             raise Error, 'position not in range'
  410.         
  411.         self._soundpos = pos
  412.         self._ssnd_seek_needed = 1
  413.  
  414.     
  415.     def readframes(self, nframes):
  416.         if self._ssnd_seek_needed:
  417.             self._ssnd_chunk.seek(0)
  418.             dummy = self._ssnd_chunk.read(8)
  419.             pos = self._soundpos * self._framesize
  420.             if pos:
  421.                 self._ssnd_chunk.seek(pos + 8)
  422.             
  423.             self._ssnd_seek_needed = 0
  424.         
  425.         if nframes == 0:
  426.             return ''
  427.         
  428.         data = self._ssnd_chunk.read(nframes * self._framesize)
  429.         if self._convert and data:
  430.             data = self._convert(data)
  431.         
  432.         self._soundpos = self._soundpos + len(data) / self._nchannels * self._sampwidth
  433.         return data
  434.  
  435.     
  436.     def _decomp_data(self, data):
  437.         import cl
  438.         dummy = self._decomp.SetParam(cl.FRAME_BUFFER_SIZE, len(data) * 2)
  439.         return self._decomp.Decompress(len(data) / self._nchannels, data)
  440.  
  441.     
  442.     def _ulaw2lin(self, data):
  443.         import audioop as audioop
  444.         return audioop.ulaw2lin(data, 2)
  445.  
  446.     
  447.     def _adpcm2lin(self, data):
  448.         import audioop
  449.         if not hasattr(self, '_adpcmstate'):
  450.             self._adpcmstate = None
  451.         
  452.         (data, self._adpcmstate) = audioop.adpcm2lin(data, 2, self._adpcmstate)
  453.         return data
  454.  
  455.     
  456.     def _read_comm_chunk(self, chunk):
  457.         self._nchannels = _read_short(chunk)
  458.         self._nframes = _read_long(chunk)
  459.         self._sampwidth = (_read_short(chunk) + 7) / 8
  460.         self._framerate = int(_read_float(chunk))
  461.         self._framesize = self._nchannels * self._sampwidth
  462.         if self._aifc:
  463.             kludge = 0
  464.             if chunk.chunksize == 18:
  465.                 kludge = 1
  466.                 print 'Warning: bad COMM chunk size'
  467.                 chunk.chunksize = 23
  468.             
  469.             self._comptype = chunk.read(4)
  470.             if kludge:
  471.                 length = ord(chunk.file.read(1))
  472.                 if length & 1 == 0:
  473.                     length = length + 1
  474.                 
  475.                 chunk.chunksize = chunk.chunksize + length
  476.                 chunk.file.seek(-1, 1)
  477.             
  478.             self._compname = _read_string(chunk)
  479.             if self._comptype != 'NONE':
  480.                 if self._comptype == 'G722':
  481.                     
  482.                     try:
  483.                         import audioop
  484.                     except ImportError:
  485.                         pass
  486.  
  487.                     self._convert = self._adpcm2lin
  488.                     self._framesize = self._framesize / 4
  489.                     return None
  490.                 
  491.                 
  492.                 try:
  493.                     import cl
  494.                 except ImportError:
  495.                     if self._comptype == 'ULAW':
  496.                         
  497.                         try:
  498.                             import audioop
  499.                             self._convert = self._ulaw2lin
  500.                             self._framesize = self._framesize / 2
  501.                             return None
  502.                         except ImportError:
  503.                             pass
  504.                         except:
  505.                             None<EXCEPTION MATCH>ImportError
  506.                         
  507.  
  508.                     None<EXCEPTION MATCH>ImportError
  509.                     raise Error, 'cannot read compressed AIFF-C files'
  510.  
  511.                 if self._comptype == 'ULAW':
  512.                     scheme = cl.G711_ULAW
  513.                     self._framesize = self._framesize / 2
  514.                 elif self._comptype == 'ALAW':
  515.                     scheme = cl.G711_ALAW
  516.                     self._framesize = self._framesize / 2
  517.                 else:
  518.                     raise Error, 'unsupported compression type'
  519.                 self._decomp = cl.OpenDecompressor(scheme)
  520.                 self._convert = self._decomp_data
  521.             
  522.         else:
  523.             self._comptype = 'NONE'
  524.             self._compname = 'not compressed'
  525.  
  526.     
  527.     def _readmark(self, chunk):
  528.         nmarkers = _read_short(chunk)
  529.         
  530.         try:
  531.             for i in range(nmarkers):
  532.                 id = _read_short(chunk)
  533.                 pos = _read_long(chunk)
  534.                 name = _read_string(chunk)
  535.                 if pos or name:
  536.                     self._markers.append((id, pos, name))
  537.                     continue
  538.         except EOFError:
  539.             print 'Warning: MARK chunk contains only', len(self._markers),
  540.             if len(self._markers) == 1:
  541.                 print 'marker',
  542.             else:
  543.                 print 'markers',
  544.             print 'instead of', nmarkers
  545.  
  546.  
  547.  
  548.  
  549. class Aifc_write:
  550.     
  551.     def __init__(self, f):
  552.         if type(f) == type(''):
  553.             filename = f
  554.             f = __builtin__.open(f, 'wb')
  555.         else:
  556.             filename = '???'
  557.         self.initfp(f)
  558.         if filename[-5:] == '.aiff':
  559.             self._aifc = 0
  560.         else:
  561.             self._aifc = 1
  562.  
  563.     
  564.     def initfp(self, file):
  565.         self._file = file
  566.         self._version = _AIFC_version
  567.         self._comptype = 'NONE'
  568.         self._compname = 'not compressed'
  569.         self._comp = None
  570.         self._convert = None
  571.         self._nchannels = 0
  572.         self._sampwidth = 0
  573.         self._framerate = 0
  574.         self._nframes = 0
  575.         self._nframeswritten = 0
  576.         self._datawritten = 0
  577.         self._datalength = 0
  578.         self._markers = []
  579.         self._marklength = 0
  580.         self._aifc = 1
  581.  
  582.     
  583.     def __del__(self):
  584.         if self._file:
  585.             self.close()
  586.         
  587.  
  588.     
  589.     def aiff(self):
  590.         if self._nframeswritten:
  591.             raise Error, 'cannot change parameters after starting to write'
  592.         
  593.         self._aifc = 0
  594.  
  595.     
  596.     def aifc(self):
  597.         if self._nframeswritten:
  598.             raise Error, 'cannot change parameters after starting to write'
  599.         
  600.         self._aifc = 1
  601.  
  602.     
  603.     def setnchannels(self, nchannels):
  604.         if self._nframeswritten:
  605.             raise Error, 'cannot change parameters after starting to write'
  606.         
  607.         if nchannels < 1:
  608.             raise Error, 'bad # of channels'
  609.         
  610.         self._nchannels = nchannels
  611.  
  612.     
  613.     def getnchannels(self):
  614.         if not self._nchannels:
  615.             raise Error, 'number of channels not set'
  616.         
  617.         return self._nchannels
  618.  
  619.     
  620.     def setsampwidth(self, sampwidth):
  621.         if self._nframeswritten:
  622.             raise Error, 'cannot change parameters after starting to write'
  623.         
  624.         if sampwidth < 1 or sampwidth > 4:
  625.             raise Error, 'bad sample width'
  626.         
  627.         self._sampwidth = sampwidth
  628.  
  629.     
  630.     def getsampwidth(self):
  631.         if not self._sampwidth:
  632.             raise Error, 'sample width not set'
  633.         
  634.         return self._sampwidth
  635.  
  636.     
  637.     def setframerate(self, framerate):
  638.         if self._nframeswritten:
  639.             raise Error, 'cannot change parameters after starting to write'
  640.         
  641.         if framerate <= 0:
  642.             raise Error, 'bad frame rate'
  643.         
  644.         self._framerate = framerate
  645.  
  646.     
  647.     def getframerate(self):
  648.         if not self._framerate:
  649.             raise Error, 'frame rate not set'
  650.         
  651.         return self._framerate
  652.  
  653.     
  654.     def setnframes(self, nframes):
  655.         if self._nframeswritten:
  656.             raise Error, 'cannot change parameters after starting to write'
  657.         
  658.         self._nframes = nframes
  659.  
  660.     
  661.     def getnframes(self):
  662.         return self._nframeswritten
  663.  
  664.     
  665.     def setcomptype(self, comptype, compname):
  666.         if self._nframeswritten:
  667.             raise Error, 'cannot change parameters after starting to write'
  668.         
  669.         if comptype not in ('NONE', 'ULAW', 'ALAW', 'G722'):
  670.             raise Error, 'unsupported compression type'
  671.         
  672.         self._comptype = comptype
  673.         self._compname = compname
  674.  
  675.     
  676.     def getcomptype(self):
  677.         return self._comptype
  678.  
  679.     
  680.     def getcompname(self):
  681.         return self._compname
  682.  
  683.     
  684.     def setparams(self, .1):
  685.         (nchannels, sampwidth, framerate, nframes, comptype, compname) = .1
  686.         if self._nframeswritten:
  687.             raise Error, 'cannot change parameters after starting to write'
  688.         
  689.         if comptype not in ('NONE', 'ULAW', 'ALAW', 'G722'):
  690.             raise Error, 'unsupported compression type'
  691.         
  692.         self.setnchannels(nchannels)
  693.         self.setsampwidth(sampwidth)
  694.         self.setframerate(framerate)
  695.         self.setnframes(nframes)
  696.         self.setcomptype(comptype, compname)
  697.  
  698.     
  699.     def getparams(self):
  700.         if not (self._nchannels) and not (self._sampwidth) or not (self._framerate):
  701.             raise Error, 'not all parameters set'
  702.         
  703.         return (self._nchannels, self._sampwidth, self._framerate, self._nframes, self._comptype, self._compname)
  704.  
  705.     
  706.     def setmark(self, id, pos, name):
  707.         if id <= 0:
  708.             raise Error, 'marker ID must be > 0'
  709.         
  710.         if pos < 0:
  711.             raise Error, 'marker position must be >= 0'
  712.         
  713.         if type(name) != type(''):
  714.             raise Error, 'marker name must be a string'
  715.         
  716.         for i in range(len(self._markers)):
  717.             if id == self._markers[i][0]:
  718.                 self._markers[i] = (id, pos, name)
  719.                 return None
  720.                 continue
  721.         
  722.         self._markers.append((id, pos, name))
  723.  
  724.     
  725.     def getmark(self, id):
  726.         for marker in self._markers:
  727.             if id == marker[0]:
  728.                 return marker
  729.                 continue
  730.         
  731.         raise Error, 'marker %r does not exist' % (id,)
  732.  
  733.     
  734.     def getmarkers(self):
  735.         if len(self._markers) == 0:
  736.             return None
  737.         
  738.         return self._markers
  739.  
  740.     
  741.     def tell(self):
  742.         return self._nframeswritten
  743.  
  744.     
  745.     def writeframesraw(self, data):
  746.         self._ensure_header_written(len(data))
  747.         nframes = len(data) / self._sampwidth * self._nchannels
  748.         if self._convert:
  749.             data = self._convert(data)
  750.         
  751.         self._file.write(data)
  752.         self._nframeswritten = self._nframeswritten + nframes
  753.         self._datawritten = self._datawritten + len(data)
  754.  
  755.     
  756.     def writeframes(self, data):
  757.         self.writeframesraw(data)
  758.         if self._nframeswritten != self._nframes or self._datalength != self._datawritten:
  759.             self._patchheader()
  760.         
  761.  
  762.     
  763.     def close(self):
  764.         self._ensure_header_written(0)
  765.         if self._datawritten & 1:
  766.             self._file.write(chr(0))
  767.             self._datawritten = self._datawritten + 1
  768.         
  769.         self._writemarkers()
  770.         if self._nframeswritten != self._nframes and self._datalength != self._datawritten or self._marklength:
  771.             self._patchheader()
  772.         
  773.         if self._comp:
  774.             self._comp.CloseCompressor()
  775.             self._comp = None
  776.         
  777.         self._file.flush()
  778.         self._file = None
  779.  
  780.     
  781.     def _comp_data(self, data):
  782.         import cl
  783.         dummy = self._comp.SetParam(cl.FRAME_BUFFER_SIZE, len(data))
  784.         dummy = self._comp.SetParam(cl.COMPRESSED_BUFFER_SIZE, len(data))
  785.         return self._comp.Compress(self._nframes, data)
  786.  
  787.     
  788.     def _lin2ulaw(self, data):
  789.         import audioop
  790.         return audioop.lin2ulaw(data, 2)
  791.  
  792.     
  793.     def _lin2adpcm(self, data):
  794.         import audioop
  795.         if not hasattr(self, '_adpcmstate'):
  796.             self._adpcmstate = None
  797.         
  798.         (data, self._adpcmstate) = audioop.lin2adpcm(data, 2, self._adpcmstate)
  799.         return data
  800.  
  801.     
  802.     def _ensure_header_written(self, datasize):
  803.         if not self._nframeswritten:
  804.             if self._comptype in ('ULAW', 'ALAW'):
  805.                 if not self._sampwidth:
  806.                     self._sampwidth = 2
  807.                 
  808.                 if self._sampwidth != 2:
  809.                     raise Error, 'sample width must be 2 when compressing with ULAW or ALAW'
  810.                 
  811.             
  812.             if self._comptype == 'G722':
  813.                 if not self._sampwidth:
  814.                     self._sampwidth = 2
  815.                 
  816.                 if self._sampwidth != 2:
  817.                     raise Error, 'sample width must be 2 when compressing with G7.22 (ADPCM)'
  818.                 
  819.             
  820.             if not self._nchannels:
  821.                 raise Error, '# channels not specified'
  822.             
  823.             if not self._sampwidth:
  824.                 raise Error, 'sample width not specified'
  825.             
  826.             if not self._framerate:
  827.                 raise Error, 'sampling rate not specified'
  828.             
  829.             self._write_header(datasize)
  830.         
  831.  
  832.     
  833.     def _init_compression(self):
  834.         if self._comptype == 'G722':
  835.             self._convert = self._lin2adpcm
  836.             return None
  837.         
  838.         
  839.         try:
  840.             import cl
  841.         except ImportError:
  842.             if self._comptype == 'ULAW':
  843.                 
  844.                 try:
  845.                     import audioop
  846.                     self._convert = self._lin2ulaw
  847.                     return None
  848.                 except ImportError:
  849.                     pass
  850.                 except:
  851.                     None<EXCEPTION MATCH>ImportError
  852.                 
  853.  
  854.             None<EXCEPTION MATCH>ImportError
  855.             raise Error, 'cannot write compressed AIFF-C files'
  856.  
  857.         if self._comptype == 'ULAW':
  858.             scheme = cl.G711_ULAW
  859.         elif self._comptype == 'ALAW':
  860.             scheme = cl.G711_ALAW
  861.         else:
  862.             raise Error, 'unsupported compression type'
  863.         self._comp = cl.OpenCompressor(scheme)
  864.         params = [
  865.             cl.ORIGINAL_FORMAT,
  866.             0,
  867.             cl.BITS_PER_COMPONENT,
  868.             self._sampwidth * 8,
  869.             cl.FRAME_RATE,
  870.             self._framerate,
  871.             cl.FRAME_BUFFER_SIZE,
  872.             100,
  873.             cl.COMPRESSED_BUFFER_SIZE,
  874.             100]
  875.         if self._nchannels == 1:
  876.             params[1] = cl.MONO
  877.         elif self._nchannels == 2:
  878.             params[1] = cl.STEREO_INTERLEAVED
  879.         else:
  880.             raise Error, 'cannot compress more than 2 channels'
  881.         self._comp.SetParams(params)
  882.         dummy = self._comp.Compress(0, '')
  883.         self._convert = self._comp_data
  884.  
  885.     
  886.     def _write_header(self, initlength):
  887.         if self._aifc and self._comptype != 'NONE':
  888.             self._init_compression()
  889.         
  890.         self._file.write('FORM')
  891.         if not self._nframes:
  892.             self._nframes = initlength / self._nchannels * self._sampwidth
  893.         
  894.         self._datalength = self._nframes * self._nchannels * self._sampwidth
  895.         if self._datalength & 1:
  896.             self._datalength = self._datalength + 1
  897.         
  898.         if self._aifc:
  899.             if self._comptype in ('ULAW', 'ALAW'):
  900.                 self._datalength = self._datalength / 2
  901.                 if self._datalength & 1:
  902.                     self._datalength = self._datalength + 1
  903.                 
  904.             elif self._comptype == 'G722':
  905.                 self._datalength = (self._datalength + 3) / 4
  906.                 if self._datalength & 1:
  907.                     self._datalength = self._datalength + 1
  908.                 
  909.             
  910.         
  911.         self._form_length_pos = self._file.tell()
  912.         commlength = self._write_form_length(self._datalength)
  913.         if self._aifc:
  914.             self._file.write('AIFC')
  915.             self._file.write('FVER')
  916.             _write_long(self._file, 4)
  917.             _write_long(self._file, self._version)
  918.         else:
  919.             self._file.write('AIFF')
  920.         self._file.write('COMM')
  921.         _write_long(self._file, commlength)
  922.         _write_short(self._file, self._nchannels)
  923.         self._nframes_pos = self._file.tell()
  924.         _write_long(self._file, self._nframes)
  925.         _write_short(self._file, self._sampwidth * 8)
  926.         _write_float(self._file, self._framerate)
  927.         if self._aifc:
  928.             self._file.write(self._comptype)
  929.             _write_string(self._file, self._compname)
  930.         
  931.         self._file.write('SSND')
  932.         self._ssnd_length_pos = self._file.tell()
  933.         _write_long(self._file, self._datalength + 8)
  934.         _write_long(self._file, 0)
  935.         _write_long(self._file, 0)
  936.  
  937.     
  938.     def _write_form_length(self, datalength):
  939.         if self._aifc:
  940.             commlength = 23 + len(self._compname)
  941.             if commlength & 1:
  942.                 commlength = commlength + 1
  943.             
  944.             verslength = 12
  945.         else:
  946.             commlength = 18
  947.             verslength = 0
  948.         _write_long(self._file, 4 + verslength + self._marklength + 8 + commlength + 16 + datalength)
  949.         return commlength
  950.  
  951.     
  952.     def _patchheader(self):
  953.         curpos = self._file.tell()
  954.         if self._datawritten & 1:
  955.             datalength = self._datawritten + 1
  956.             self._file.write(chr(0))
  957.         else:
  958.             datalength = self._datawritten
  959.         if datalength == self._datalength and self._nframes == self._nframeswritten and self._marklength == 0:
  960.             self._file.seek(curpos, 0)
  961.             return None
  962.         
  963.         self._file.seek(self._form_length_pos, 0)
  964.         dummy = self._write_form_length(datalength)
  965.         self._file.seek(self._nframes_pos, 0)
  966.         _write_long(self._file, self._nframeswritten)
  967.         self._file.seek(self._ssnd_length_pos, 0)
  968.         _write_long(self._file, datalength + 8)
  969.         self._file.seek(curpos, 0)
  970.         self._nframes = self._nframeswritten
  971.         self._datalength = datalength
  972.  
  973.     
  974.     def _writemarkers(self):
  975.         if len(self._markers) == 0:
  976.             return None
  977.         
  978.         self._file.write('MARK')
  979.         length = 2
  980.         for marker in self._markers:
  981.             (id, pos, name) = marker
  982.             length = length + len(name) + 1 + 6
  983.             if len(name) & 1 == 0:
  984.                 length = length + 1
  985.                 continue
  986.         
  987.         _write_long(self._file, length)
  988.         self._marklength = length + 8
  989.         _write_short(self._file, len(self._markers))
  990.         for marker in self._markers:
  991.             (id, pos, name) = marker
  992.             _write_short(self._file, id)
  993.             _write_long(self._file, pos)
  994.             _write_string(self._file, name)
  995.         
  996.  
  997.  
  998.  
  999. def open(f, mode = None):
  1000.     if mode is None:
  1001.         if hasattr(f, 'mode'):
  1002.             mode = f.mode
  1003.         else:
  1004.             mode = 'rb'
  1005.     
  1006.     if mode in ('r', 'rb'):
  1007.         return Aifc_read(f)
  1008.     elif mode in ('w', 'wb'):
  1009.         return Aifc_write(f)
  1010.     else:
  1011.         raise Error, "mode must be 'r', 'rb', 'w', or 'wb'"
  1012.  
  1013. openfp = open
  1014. if __name__ == '__main__':
  1015.     import sys
  1016.     if not sys.argv[1:]:
  1017.         sys.argv.append('/usr/demos/data/audio/bach.aiff')
  1018.     
  1019.     fn = sys.argv[1]
  1020.     f = open(fn, 'r')
  1021.     print 'Reading', fn
  1022.     print 'nchannels =', f.getnchannels()
  1023.     print 'nframes   =', f.getnframes()
  1024.     print 'sampwidth =', f.getsampwidth()
  1025.     print 'framerate =', f.getframerate()
  1026.     print 'comptype  =', f.getcomptype()
  1027.     print 'compname  =', f.getcompname()
  1028.     if sys.argv[2:]:
  1029.         gn = sys.argv[2]
  1030.         print 'Writing', gn
  1031.         g = open(gn, 'w')
  1032.         g.setparams(f.getparams())
  1033.         while None:
  1034.             data = f.readframes(1024)
  1035.             if not data:
  1036.                 break
  1037.             
  1038.             continue
  1039.             g.close()
  1040.             f.close()
  1041.             print 'Done.'
  1042.     sys.argv[2:]
  1043.  
  1044.